package com.gepengjun.lims.config.shiro;

import com.gepengjun.lims.entity.Permission;
import com.gepengjun.lims.entity.Role;
import com.gepengjun.lims.entity.User;
import com.gepengjun.lims.service.PermissionService;
import com.gepengjun.lims.service.RoleService;
import com.gepengjun.lims.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

public class MyShiroRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);

    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    @Resource
    private PermissionService permissionService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    //用户登录次数计数  redisKey 前缀
    private String SHIRO_LOGIN_COUNT = "shiro_login_count_";

    //用户登录是否被锁定    一小时 redisKey 前缀
    private String SHIRO_IS_LOCK = "shiro_is_lock_";

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection collection) {
        System.out.println("权限配置--------doGetAuthorizationInfo");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        User user = (User) collection.getPrimaryPrincipal();
        List<Role> roleList = roleService.findRolesByUserId(user.getUserId());
        if (roleList != null){
            for (Role role:roleList){
                info.addRole(role.getRoleName());
            }
        }

        List<Permission> permissionList = permissionService.findByUserId(user.getUserId());

        if (permissionList != null){
            for (Permission permission:permissionList){
                info.addStringPermission(permission.getPermissionStr());
            }
        }
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        logger.info("登录验证--------doGetAuthenticationInfo");
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        String username = token.getUsername();
        String password = String.valueOf(token.getPassword());

        //访问一次，计数一次
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        opsForValue.increment(SHIRO_LOGIN_COUNT + username, 1);

        if ("LOCK".equals(opsForValue.get(SHIRO_IS_LOCK + username))) {
            throw new LockedAccountException();
        }

        String salt = ((Object) new SimpleHash("MD5", username, username, 2)).toString();
        String passwordMd5 = ((Object) new SimpleHash("MD5", password, username + salt, 2)).toString();
        List<User> userList = userService.findByUsernameAndPassword(username,passwordMd5);

        if (userList == null || userList.size() < 1) {
            System.out.println("帐号或密码不正确");
            logger.info("doGetAuthenticationInfo:帐号或密码不正确");
            throw new AccountException();
        } else{
            User user = userList.get(0);
            logger.info("doGetAuthenticationInfo:user.getStatus():"+user.getStatus());
            if (!user.getStatus()) {

                 /*如果用户的status为禁用那么就抛出<code>DisabledAccountException</code>*/


                System.out.println("此帐号已经设置为禁止登录");
                opsForValue.set(SHIRO_LOGIN_COUNT + username, "0");
                throw new DisabledAccountException("此帐号已经设置为禁止登录！");
            } else {
                //登录成功
                //更新登录时间 last login time
                user.setLastLoginTime(new Date());
                userService.updateById(user);
                Session session = SecurityUtils.getSubject().getSession();
                session.setAttribute("user",user);
                //清空登录计数
                opsForValue.set(SHIRO_LOGIN_COUNT + username, "0");
                SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(),
                        ByteSource.Util.bytes(user.getCreditialsSalt()), user.getRealName());
                logger.info("doGetAuthenticationInfo:登陆验证完毕");
                return info;
            }
        }
    }
}
